#include "print.h"
#include "init.h"
#include "debug.h"
#include "memory.h"
#include "thread.h"
#include "interrupt.h"
#include "console.h"
#include "process.h"
#include "syscall-init.h"
#include "syscall.h"
#include "stdio.h"
#include "fs.h"
#include "string.h"
#include "dir.h"
#include "shell.h"
#include "assert.h"
#include "ide.h"
#include "stdio-kernel.h"

extern void cls_screen(void);

void k_thread_a(void *arg);
void k_thread_b(void *arg);
void u_prog_a(void);
void u_prog_b(void);

void init(void);


int main(void)
{
    put_str("I am kernel\n");
    init_all();

    // uint32_t file_size = 14452;
    // uint32_t sec_cnt = DIV_ROUND_UP(file_size, 512);
    // struct disk *sda = &channels[0].devices[0];
    // void *prog_buf = sys_malloc(file_size);
    // ide_read(sda, 600, prog_buf, sec_cnt);
    // int32_t fd = sys_open("/prog_no_arg", O_CREAT | O_RDWR);
    // if (fd != -1) {
    //     if (sys_write(fd, prog_buf, file_size) == -1) {
    //         printk("file write error!\n");
    //         while(1)
    //             ;
    //     }
    // }

    cls_screen();
    printf("\\   Operating  / | |\\    | |--    /---     ---     ---\n");
    printf(" \\   System!  /  | | \\   | |  \\  /        /       /   \\\n");
    printf("  \\    /\\    /   | |  \\  | |   |  \\--\\   |  --\\  |     |\n");
    printf("   \\  /  \\  /    | |   \\ | |  /       \\   \\   /   \\   / \n");
    printf("    \\/    \\/     | |    \\| |--    ---/     ---     ---\n");
    print_prompt();

    intr_enable(); //开中断
    // void *addr = get_kernel_pages(3);
    // put_str("\nget_kernel_page start vaddr is ");
    // put_int((uint32_t)addr);
    // put_str("\n");

    // 写入应用程序

    

    // process_execute(u_prog_a, "user_prog_a");
    // process_execute(u_prog_b, "user_prog_b");
    // 等开断后由时钟中断发起调度

    // console_put_str(" main_pid:0x");
    // console_put_int(sys_getpid());
    // console_put_char('\n');

    // thread_start("k_thread_a", 31, k_thread_a, "I am thread_a ");
    // thread_start("k_thread_b", 31, k_thread_b, "I am threan_b ");

    /********  测试代码  ********/

    // int fd = sys_open("/file1", O_CREAT);

    // sys_close(fd);

    // if (sys_mkdir("/dir1") == -1){
    //     printf("mkdir fail\n");
    // }
    
    // fd = sys_open("/file1", O_RDWR);
    // if (fd == -1) {
    //     printf("open failed\n");
    // } else {
    //     char buf[64] = {0};
    //     sys_lseek(fd, 0, SEEK_SET);
    //     sys_read(fd, buf, 64);
    //     printf("/file1:\"%s\"\n", buf);
    //     if (sys_close(fd) != -1)
    //     {
    //         printf("closed\n");
    //     }
    // }

    // struct stat obj_stat;
    // sys_stat("/", &obj_stat);
    // printf("/ \'s info\n    i_no: %d\n    size: %d\n    fltp: %s\n",
    //        obj_stat.st_ino, obj_stat.st_size, obj_stat.st_filetype == FT_DIRECTORY ? "dir" : "regular");
    // sys_stat("/dir1", &obj_stat);
    // printf("/dir1 \'s info\n    i_no: %d\n    size: %d\n    fltp: %s\n",
    //        obj_stat.st_ino, obj_stat.st_size, obj_stat.st_filetype == FT_DIRECTORY ? "dir" : "regular");
    // sys_stat("/file1", &obj_stat);
    // printf("/file1 \'s info\n    i_no: %d\n    size: %d\n    fltp: %s\n",
    //        obj_stat.st_ino, obj_stat.st_size, obj_stat.st_filetype == FT_DIRECTORY ? "dir" : "regular");
    /********  测试代码  ********/
    /*
    printf("/dir1/subdir1 create %s!\n", sys_mkdir("/dir1/subdir1") == 0 ? "done" : "fail");
    printf("/dir1 create %s!\n", sys_mkdir("/dir1") == 0 ? "done" : "fail");
    printf("now, /dir1/subdir1 create %s!\n", sys_mkdir("/dir1/subdir1") == 0 ? "done" : "fail");
    int fd = sys_open("/dir1/subdir1/file2", O_CREAT | O_RDWR);
    if (fd != -1)
    {
        printf("/dir1/subdir1/file2 create done!\n");
        sys_write(fd, "Catch me if you can!\n", 21);
        sys_lseek(fd, 0, SEEK_SET);
        char buf[32] = {0};
        sys_read(fd, buf, 21);
        printf("/dir1/subdir1/file2 says:\n%s", buf);
        sys_close(fd);
    }

    struct dir *p_dir = sys_opendir("/dir1/subdir1");
    if (p_dir)
    {
        printf("/dir1/subdir1 open done!\n");
        if (sys_closedir(p_dir) == 0)
        {
            printf("/dir1/subdir1 close done!\n");
        }
        else
        {
            printf("/dir1/subdir1 close fail!\n");
        }
    }
    else
    {
        printf("/dir1/subdir1 open fail!\n");
    }
*/

    while (1)
    {
        //console_put_str("M ");
    }
    // ASSERT(1==2);
    return 0;
}

/* init进程，要获取到pid=1，需要最先创建 */
void init(void) {
    
    uint32_t ret_pid = fork();

    if (ret_pid) {
        // 返回给父进程的pid是子进程的pid号
        while(1)
            ;
    }
    else
    {
        // 返回给子进程的pid是0
        my_shell();
    }
    panic("init: should not be here");
}

void k_thread_a(void *arg)
{
    char *para = (char *)arg;
    void *addr1 = sys_malloc(256);
    void *addr2 = sys_malloc(255);
    void *addr3 = sys_malloc(254);
    console_put_str(" thread_a malloc addr:0x");
    console_put_int((int)addr1);
    console_put_char(',');
    console_put_int((int)addr2);
    console_put_char(',');
    console_put_int((int)addr3);
    console_put_char('\n');

    int cpu_delay = 100000;
    while (cpu_delay-- > 0)
        ;
    sys_free(addr1);
    sys_free(addr2);
    sys_free(addr3);
    while (1)
    {
    }
}

void k_thread_b(void *arg)
{
    char *para = (char *)arg;
    void *addr1 = sys_malloc(256);
    void *addr2 = sys_malloc(255);
    void *addr3 = sys_malloc(254);
    console_put_str(" thread_b malloc addr:0x");
    console_put_int((int)addr1);
    console_put_char(',');
    console_put_int((int)addr2);
    console_put_char(',');
    console_put_int((int)addr3);
    console_put_char('\n');

    int cpu_delay = 100000;
    while (cpu_delay-- > 0)
        ;
    sys_free(addr1);
    sys_free(addr2);
    sys_free(addr3);
    while (1)
    {
    }
}

void u_prog_a(void)
{
    // void *addr1 = malloc(256);
    // void *addr2 = malloc(255);
    // void *addr3 = malloc(254);
    // printf(" prog_a malloc addr:0x%x,0x%x,0x%x\n",
    //        (int)addr1, (int)addr2, (int)addr3);
    // int cpu_delay = 100000;
    // while (cpu_delay-- > 0)
    //     ;
    // free(addr1);
    // free(addr2);
    // free(addr3);
    while (1)
    {

    }
}

void u_prog_b(void)
{
    void *addr1 = malloc(256);
    void *addr2 = malloc(255);
    void *addr3 = malloc(254);
    printf(" prog_b malloc addr:0x%x,0x%x,0x%x\n",
           (int)addr1, (int)addr2, (int)addr3);
    int cpu_delay = 100000;
    while (cpu_delay-- > 0)
        ;
    free(addr1);
    free(addr2);
    free(addr3);
    while (1)
    {
    }
}

// 测试键盘缓冲区时的代码

// void k_thread_a(void *arg){
//     char *para = (char *)arg;
//     while(1) {
//         enum intr_status old_status = intr_disable();
//         if (!ioq_empty(&kbd_buf)) {
//             console_put_str(para);
//             char byte = ioq_getchar(&kbd_buf);
//             console_put_char(byte);
//         }
//         intr_set_status(old_status);
//     }
// }

// void k_thread_b(void *arg){
//     char *para = (char *)arg;
//     while(1) {
//         enum intr_status old_status = intr_disable();
//         if (!ioq_empty(&kbd_buf)) {
//             console_put_str(para);
//             char byte = ioq_getchar(&kbd_buf);
//             console_put_char(byte);
//         }
//         intr_set_status(old_status);
//     }
// }